from PIL import Image
import io
import logging
from typing import Dict, Optional
import tempfile
import os
from app.utils.file_utils import temp_file_manager

# 设置日志
logger = logging.getLogger(__name__)

class ImageService:
    # 证件照尺寸配置（宽x高，单位：像素）
    PHOTO_SIZES = {
        "one_inch": (295, 413),     # 一寸
        "two_inch": (413, 579),     # 二寸
        "small_two": (390, 567),    # 小二寸
        "passport": (413, 531),     # 护照
        "id_card": (358, 441),      # 身份证
        "visa": (390, 567),         # 签证
        "driving": (358, 441),      # 驾照
        "work": (413, 531),         # 工作证
        "graduate": (413, 531),     # 毕业照
    }

    @staticmethod
    async def resize_photo(content: bytes, photo_type: str, bg_color: str = "white", format: str = "jpg") -> bytes:
        """
        调整证件照尺寸
        
        Args:
            content: 图片内容
            photo_type: 证件照类型
            bg_color: 背景颜色
            format: 输出格式
            
        Returns:
            bytes: 处理后的图片内容
        """
        if not photo_type or photo_type not in ImageService.PHOTO_SIZES:
            raise ValueError(f"不支持的证件照类型: {photo_type}")
            
        with temp_file_manager() as tmp_mgr:
            try:
                # 打开图片
                img = Image.open(io.BytesIO(content))
                
                # 转换为RGB模式
                if img.mode != 'RGB':
                    img = img.convert('RGB')
                    
                # 获取目标尺寸
                target_width, target_height = ImageService.PHOTO_SIZES[photo_type]
                
                # 创建新图片（带背景色）
                new_img = Image.new('RGB', (target_width, target_height), bg_color)
                
                # 调整原图尺寸并保持比例
                ratio = min(target_width/img.width, target_height/img.height)
                new_size = (int(img.width * ratio), int(img.height * ratio))
                resized_img = img.resize(new_size, Image.Resampling.LANCZOS)
                
                # 将调整后的图片粘贴到中心位置
                x = (target_width - new_size[0]) // 2
                y = (target_height - new_size[1]) // 2
                new_img.paste(resized_img, (x, y))
                
                # 保存为字节流
                output = io.BytesIO()
                new_img.save(output, format=format.upper())
                return output.getvalue()
                
            except Exception as e:
                logger.error(f"调整照片尺寸失败: {str(e)}")
                raise

    @staticmethod
    async def resize_image(content: bytes, width: int, height: int) -> bytes:
        """
        调整图片尺寸
        
        Args:
            content: 图片内容
            width: 目标宽度
            height: 目标高度
        
        Returns:
            bytes: 处理后的图片内容
        """
        try:
            with Image.open(io.BytesIO(content)) as img:
                # 转换为RGB模式
                if img.mode != 'RGB':
                    img = img.convert('RGB')

                # 调整尺寸
                resized_img = img.resize((width, height), Image.Resampling.LANCZOS)

                # 保存处理后的图片
                output = io.BytesIO()
                resized_img.save(output, format=img.format or 'JPEG')
                return output.getvalue()

        except Exception as e:
            logger.error(f"调整图片尺寸失败: {str(e)}")
            raise

# 格式映射
FORMAT_MAPPING = {
    'jpg': 'JPEG',
    'jpeg': 'JPEG',
    'png': 'PNG',
    'webp': 'WEBP'
}

async def convert_format(content: bytes, format: str) -> bytes:
    """转换图片格式"""
    try:
        format = format.lower()
        if format not in FORMAT_MAPPING:
            raise ValueError(f"不支持的图片格式: {format}")
            
        img = Image.open(io.BytesIO(content))
        logger.info(f"原始图片格式: {img.format}, 模式: {img.mode}")
        
        output = io.BytesIO()
        save_format = FORMAT_MAPPING[format]
        
        # 处理透明图片
        if img.mode == 'RGBA' and format in ['jpg', 'jpeg']:
            background = Image.new('RGB', img.size, 'white')
            background.paste(img, mask=img.split()[3])
            img = background
        
        logger.info(f"保存格式: {save_format}")
        img.save(output, format=save_format, quality=95)
        return output.getvalue()
        
    except Exception as e:
        logger.error(f"格式转换失败: {str(e)}", exc_info=True)
        raise Exception(f"格式转换失败: {str(e)}")

async def crop_image(
    content: bytes,
    x: int,
    y: int,
    width: int,
    height: int,
    format: str = "jpg"
) -> bytes:
    """裁剪图片"""
    try:
        format = format.lower()
        if format not in FORMAT_MAPPING:
            raise ValueError(f"不支持的图片格式: {format}")
            
        img = Image.open(io.BytesIO(content))
        logger.info(f"原始图片大小: {img.size}, 裁剪区域: ({x}, {y}, {width}, {height})")
        
        # 验证裁剪区域
        if x < 0 or y < 0 or width <= 0 or height <= 0:
            raise ValueError("无效的裁剪参数")
        if x + width > img.width or y + height > img.height:
            raise ValueError("裁剪区域超出图片范围")
            
        cropped = img.crop((x, y, x + width, y + height))
        
        output = io.BytesIO()
        save_format = FORMAT_MAPPING[format]
        logger.info(f"保存格式: {save_format}")
        cropped.save(output, format=save_format, quality=95)
        return output.getvalue()
        
    except Exception as e:
        logger.error(f"裁剪失败: {str(e)}", exc_info=True)
        raise Exception(f"裁剪失败: {str(e)}") 